﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;
using ESRI.ArcGIS.Geometry;
using PlanningGIS.Util.Convertor;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using PlanningGIS.ArcGIS;
using PlanningGIS.MapSheet;
using System.ComponentModel;
using PlanningGIS.Win.Controls;

namespace PlanningGIS.MapSheet
{
    /// <summary>
    /// 地图图框
    /// A1  : 594mm×840mm ；
    /// A2  : 420×594mm ；
    /// A3  : 297×420mm ；
    /// A4  : 210×297mm ；
    /// A5  : 148×210mm ；
    /// A6  : 105*148mm ；
    /// B1  : 706×1000mm ；
    /// B2  : 500×706mm ；
    /// B3  : 353×500mm ；
    /// B4  : 250×353mm   ； 
    /// B5  : 176×250mm ；
    /// 
    /// 1;500图廓比例尺的默认页面大小为A1大小，地图位置居中
    /// </summary>
    public class BigFrame
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public BigFrame()
        {
            Scale = 500;
            UnitValue = 1000;
            PageWidth = 84.0;
            PageHeight = 59.4;
        }

        /// <summary>
        /// 获取或设置要打印的图幅【输入，必需】
        /// </summary>
        public Mapsheet Sheet { get; set; }

        /// <summary>
        /// 获取或设置比例尺大小【输入，必需】
        /// </summary>
        public double Scale { get; set; }

        /// <summary>
        /// 获取或设置X的偏移量【输入，非必需】
        /// </summary>
        [Description("获取或设置X的偏移量【输入，可选】")]
        public double XOffset { get; set; }

        /// <summary>
        /// 获取或设置Y的偏移量【输入，非必需】
        /// </summary>
        [Description("获取或设置Y的偏移量【输入，可选】")]
        public double YOffset { get; set; }

        /// <summary>
        /// 获取或设置单位，默认为1000（千米）【输入，可选】
        /// </summary>
        [Description("获取或设置单位，默认为1000（千米）,不能为0【输入，可选】")]
        public int UnitValue { get; set; }

        /// <summary>
        /// 获取或设置密级
        /// </summary>
        public string SecurityLevel { get; set; }

        /// <summary>
        ///  获取或设置单位
        /// </summary>
        public string UnitName { get; set; }

        /// <summary>
        /// 获取图幅经过偏移后的坐标值信息，
        /// 属性为 XMin、XMax、YMin、YMax。用来处理四个角的坐标对象
        /// </summary>
        public dynamic OffsetExtent { get; protected set; }

        /// <summary>
        /// 获取或设置关联的九宫格的图号（或图名），从左到右、从上到下【输入，可选】
        /// </summary>
        [Description("获取或设置关联的九宫格的图号（或图名），从左到右、从上到下【输入，可选】")]
        public List<string> SheetCodes { get; set; }

        /// <summary>
        /// 左下角数据信息
        /// </summary>
        protected List<string> _LeftValues = null;

        /// <summary>
        /// 右下角数据信息
        /// </summary>
        protected List<string> _RightValues = null;

        /// <summary>
        /// 获取或设置纸张的宽度，默认84.0
        /// </summary>
        public double PageWidth { get; set; }

        /// <summary>
        /// 获取或设置纸张的高度，默认59.4
        /// </summary>
        public double PageHeight { get; set; }

        /// <summary>
        /// 布局内边框范围
        /// </summary>
        public IEnvelope InnerExtent { get; private set; }

        /// <summary>
        /// 厘米
        /// </summary>
        public const string _UNIT_CM = "厘米";

        /// <summary>
        /// 毫米
        /// </summary>
        public const string _UNIT_MM = "毫米";

        /// <summary>
        /// 英寸
        /// </summary>
        public const string _UNIT_IN = "英寸";

        /// <summary>
        /// 点
        /// </summary>
        public const string _UNIT_PT = "点";
        
        /// <summary>
        /// 毫米换算到点 2.83465
        /// </summary>
        public const double _TOPT_MM = 2.83465;

        /// <summary>
        /// 英寸换算到点 72
        /// </summary>
        public const double _TOPT_IN = 72;

        /// <summary>
        /// 内外边框的距离 1.2 = 1.1+0.1 间隔+宽度
        /// </summary>
        public const double _INNER_DIS = 1.2;

        /// <summary>
        /// 布局绘制容器
        /// </summary>
        protected IGraphicsContainer _Graphics = null;

        /// <summary>
        /// 布局对象
        /// </summary>
        public IPageLayoutControl3 PageLayout { get; set; }

        /// <summary>
        /// 默认颜色
        /// </summary>
        private IRgbColor _DefaultColor = null;

        /// <summary>
        /// 进度条
        /// </summary>
        public Progressor _Progressor { get; set; }

        /// <summary>
        /// 当前地图绘制的范围
        /// </summary>
        private IEnvelope _FrameExtent = null;

        /// <summary>
        /// 在默认的A1纸张上绘制布局
        /// </summary>
        public void DrawLayout(IEnvelope extent = null)
        {
            _Graphics = (IGraphicsContainer)PageLayout.PageLayout;
            if (Sheet != null)
            {
                _FrameExtent = Sheet.Geometry.Envelope;
                //Scale = PageLayout.ActiveView.FocusMap.MapScale;
            }
            else
            {
                if (extent != null)
                {
                    _FrameExtent = extent;
                }
                else
                {
                    _FrameExtent = PageLayout.ActiveView.Extent;
                }
                //Scale = PageLayout.ActiveView.FocusMap.MapScale;
            }
            
            this.InnerExtent = new Envelope()
            {
                XMin = PageWidth / 2.0 - _FrameExtent.Width / Scale * 100 / 2.0,
                YMin = PageHeight / 2.0 - _FrameExtent.Height / Scale * 100 / 2.0,
                XMax = PageWidth / 2.0 + _FrameExtent.Width / Scale * 100 / 2.0,
                YMax = PageHeight / 2.0 + _FrameExtent.Height / Scale * 100 / 2.0
            } as IEnvelope;
            _DefaultColor = new RgbColor() { Red = 0, Green = 0, Blue = 0 };
            OffsetExtent = new ExpandoObject();
            OffsetExtent.XMin = Math.Round((_FrameExtent.XMin - XOffset) / UnitValue, 2);
            OffsetExtent.XMax = Math.Round((_FrameExtent.XMax - XOffset) / UnitValue, 2);
            OffsetExtent.YMin = Math.Round((_FrameExtent.YMin - YOffset) / UnitValue, 2);
            OffsetExtent.YMax = Math.Round((_FrameExtent.YMax - YOffset) / UnitValue, 2);

            DeleteElement();
            DrawMap();
            DrawFrame();
            DrawMapTag();
            DrawSheetTag();
            DrawBottomMeta(InnerExtent.XMin, InnerExtent.YMin - _INNER_DIS - 0.3, _LeftValues);
            DrawBottomMeta(InnerExtent.XMax - 9, InnerExtent.YMin - _INNER_DIS - 0.3, _RightValues);
        }

        /// <summary>
        /// 绘制地图
        /// </summary>
        private void DrawMap()
        {
            IMapFrame mapframe = null;            
            IElement element = null;
            _Graphics.Reset();
            while ((element = _Graphics.Next()) != null)
            {
                if (element is IMapFrame)
                {
                    mapframe = element as IMapFrame;
                    break;
                }
            }
            _Graphics.Reset();
            ISymbolBorder symBorder = (ISymbolBorder)mapframe.Border;
            ILineSymbol symLine = symBorder.LineSymbol;
            symLine.Width = 0.1 * _TOPT_MM;
            symBorder.LineSymbol = symLine;
            mapframe.Border = symBorder;
            IElement mapele = mapframe as IElement;
            mapele.Geometry = this.InnerExtent as IGeometry;
            mapframe.ExtentType = esriExtentTypeEnum.esriExtentBounds;
            mapframe.MapScale = Scale;
            mapframe.MapBounds = _FrameExtent;
            (mapframe.Map as IActiveView).Refresh();
        }

        /// <summary>
        /// 绘制框架（图廓线、密级、图阔角点、标题）
        /// </summary>
        private void DrawFrame()
        {
            //图廓线
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin - _INNER_DIS, InnerExtent.YMin, InnerExtent.XMax + _INNER_DIS, InnerExtent.YMin, _DefaultColor, 0.1 * _TOPT_MM), 8); //下
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin - _INNER_DIS, InnerExtent.YMax, InnerExtent.XMax + _INNER_DIS, InnerExtent.YMax, _DefaultColor, 0.1 * _TOPT_MM), 8); //上
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin, InnerExtent.YMin - _INNER_DIS, InnerExtent.XMin, InnerExtent.YMax + _INNER_DIS, _DefaultColor, 0.1 * _TOPT_MM), 8); //左
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMax, InnerExtent.YMin - _INNER_DIS, InnerExtent.XMax, InnerExtent.YMax + _INNER_DIS, _DefaultColor, 0.1 * _TOPT_MM), 8); //右

            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin - _INNER_DIS, InnerExtent.YMin - _INNER_DIS, InnerExtent.XMin - _INNER_DIS, InnerExtent.YMax + _INNER_DIS, _DefaultColor, 1 * _TOPT_MM), 8); //下
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin - _INNER_DIS, InnerExtent.YMax + _INNER_DIS, InnerExtent.XMax + _INNER_DIS, InnerExtent.YMax + _INNER_DIS, _DefaultColor, 1 * _TOPT_MM), 8); //上
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMax + _INNER_DIS, InnerExtent.YMax + _INNER_DIS, InnerExtent.XMax + _INNER_DIS, InnerExtent.YMin - _INNER_DIS, _DefaultColor, 1 * _TOPT_MM), 8); //左
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMax + _INNER_DIS, InnerExtent.YMin - _INNER_DIS, InnerExtent.XMin - _INNER_DIS, InnerExtent.YMin - _INNER_DIS, _DefaultColor, 1 * _TOPT_MM), 8); //右
            
            //密级
            _Graphics.AddElement(ElementHelper.CreateText(InnerExtent.XMax, InnerExtent.YMax + _INNER_DIS + 0.5, SecurityLevel, (decimal)(4 * _TOPT_MM), esriTextHorizontalAlignment.esriTHARight, esriTextVerticalAlignment.esriTVABaseline, "宋体", false, 0), 9);
            //图阔角点
            decimal fontsize = (decimal)(3 * _TOPT_MM);
            _Graphics.AddElement(ElementHelper.CreateText(InnerExtent.XMin, InnerExtent.YMin - _INNER_DIS + 0.15, ObjectConvertor.ToString(((double)OffsetExtent.XMin), 2).ToString(), fontsize, esriTextHorizontalAlignment.esriTHACenter, esriTextVerticalAlignment.esriTVABaseline, "宋体", false, 0), 9);
            _Graphics.AddElement(ElementHelper.CreateText(InnerExtent.XMin - _INNER_DIS + 0.15, InnerExtent.YMin + 0.15, ObjectConvertor.ToString(((double)OffsetExtent.YMin), 2).ToString(), fontsize, esriTextHorizontalAlignment.esriTHALeft, esriTextVerticalAlignment.esriTVABaseline, "宋体", false, 0), 9);
            _Graphics.AddElement(ElementHelper.CreateText(InnerExtent.XMin, InnerExtent.YMax + _INNER_DIS - 0.15, ObjectConvertor.ToString(((double)OffsetExtent.XMin), 2).ToString(), fontsize, esriTextHorizontalAlignment.esriTHACenter, esriTextVerticalAlignment.esriTVATop, "宋体", false, 0), 9);
            _Graphics.AddElement(ElementHelper.CreateText(InnerExtent.XMin - _INNER_DIS + 0.15, InnerExtent.YMax + 0.15, ObjectConvertor.ToString(((double)OffsetExtent.YMax), 2).ToString(), fontsize, esriTextHorizontalAlignment.esriTHALeft, esriTextVerticalAlignment.esriTVABaseline, "宋体", false, 0), 9);
            _Graphics.AddElement(ElementHelper.CreateText(InnerExtent.XMax, InnerExtent.YMax + _INNER_DIS - 0.15, ObjectConvertor.ToString(((double)OffsetExtent.XMax), 2).ToString(), fontsize, esriTextHorizontalAlignment.esriTHACenter, esriTextVerticalAlignment.esriTVATop, "黑体", false, 0), 9);
            _Graphics.AddElement(ElementHelper.CreateText(InnerExtent.XMax + _INNER_DIS - 0.15, InnerExtent.YMax + 0.15, ObjectConvertor.ToString(((double)OffsetExtent.YMax), 2).ToString(), fontsize, esriTextHorizontalAlignment.esriTHARight, esriTextVerticalAlignment.esriTVABaseline, "宋体", false, 0), 9);
            _Graphics.AddElement(ElementHelper.CreateText(InnerExtent.XMax, InnerExtent.YMin - _INNER_DIS + 0.15, ObjectConvertor.ToString(((double)OffsetExtent.XMax), 2).ToString(), fontsize, esriTextHorizontalAlignment.esriTHACenter, esriTextVerticalAlignment.esriTVABaseline, "宋体", false, 0), 9);
            _Graphics.AddElement(ElementHelper.CreateText(InnerExtent.XMax + _INNER_DIS - 0.15, InnerExtent.YMin + 0.15, ObjectConvertor.ToString(((double)OffsetExtent.YMin), 2).ToString(), fontsize, esriTextHorizontalAlignment.esriTHARight, esriTextVerticalAlignment.esriTVABaseline, "宋体", false, 0), 9);
            //标题
            if (Sheet != null)
            {
                _Graphics.AddElement(ElementHelper.CreateText(PageWidth / 2.0, InnerExtent.YMax + _INNER_DIS + 0.5, Sheet.Code, (decimal)(5 * _TOPT_MM), esriTextHorizontalAlignment.esriTHACenter, esriTextVerticalAlignment.esriTVABaseline, "宋体", false, 0), 9);
                if (!string.IsNullOrEmpty(Sheet.Name) || !string.IsNullOrWhiteSpace(Sheet.Name))
                    _Graphics.AddElement(ElementHelper.CreateText(PageWidth / 2.0, InnerExtent.YMax + _INNER_DIS + 1.3, Sheet.Name, (decimal)(6 * _TOPT_MM), esriTextHorizontalAlignment.esriTHACenter, esriTextVerticalAlignment.esriTVABaseline, "宋体", false, 0), 9);

            }
            //比例尺
            _Graphics.AddElement(ElementHelper.CreateText(PageWidth / 2.0, InnerExtent.YMin - _INNER_DIS - 0.5, "1:" + Scale.ToString(), (decimal)(4 * _TOPT_MM), esriTextHorizontalAlignment.esriTHACenter, esriTextVerticalAlignment.esriTVABaseline, "宋体", false, 0), 9);
            //单位名称
            fontsize = (decimal)(4 * _TOPT_MM);
            string strUnit = "";
            foreach (char c in UnitName)
            {
                if (strUnit == "") strUnit = c.ToString();
                else strUnit = strUnit + "\r\n" + c;
                  
            }
            _Graphics.AddElement(ElementHelper.CreateText(InnerExtent.XMin - _INNER_DIS - 0.4, InnerExtent.YMin, strUnit, fontsize, esriTextHorizontalAlignment.esriTHARight, esriTextVerticalAlignment.esriTVABottom, "宋体", false, 0), 9);
        }

        /// <summary>
        /// 绘制图面标识（横向、纵向网线十字叉及短线）
        /// </summary>
        private void DrawMapTag()
        {
            int iCrossW = (Convert.ToInt32(InnerExtent.Width / 10)) - 1;
            int iCrossH = (Convert.ToInt32(InnerExtent.Height / 10)) - 1;
            //生成网线十字叉
            for (int i = 1; i <= iCrossW; i++)
            {
                double x0 = InnerExtent.XMin + i * 10;
                for (int j = 1; j <= iCrossH; j++)
                {
                    double y0 = InnerExtent.YMin + j * 10;
                    _Graphics.AddElement(ElementHelper.CreateLine(x0 - 0.5, y0, x0 + 0.5, y0, _DefaultColor, 0.1 * _TOPT_MM), 0);
                    _Graphics.AddElement(ElementHelper.CreateLine(x0, y0 - 0.5, x0, y0 + 0.5, _DefaultColor, 0.1 * _TOPT_MM), 0);
                }
            }

            //生成坐标网线短线
            for (int i = 1; i <= iCrossH; i++)
            {
                double y0 = InnerExtent.YMin + i * 10;
                _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin, y0, InnerExtent.XMin + 0.5, y0, _DefaultColor, 0.1 * _TOPT_MM), 0);
                _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMax - 0.5, y0, InnerExtent.XMax, y0, _DefaultColor, 0.1 * _TOPT_MM), 0);
            }

            for (int i = 1; i <= iCrossW; i++)
            {
                double x0 = InnerExtent.XMin + i * 10;
                _Graphics.AddElement(ElementHelper.CreateLine(x0, InnerExtent.YMin, x0, InnerExtent.YMin + 0.5, _DefaultColor, 0.1 * _TOPT_MM), 0);
                _Graphics.AddElement(ElementHelper.CreateLine(x0, InnerExtent.YMax, x0, InnerExtent.YMax - 0.5, _DefaultColor, 0.1 * _TOPT_MM), 0);
            }
        }

        /// <summary>
        /// 绘制左上角图幅标识（九宫格）
        /// </summary>
        private void DrawSheetTag()
        {
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin, InnerExtent.YMax + 0.3 + _INNER_DIS, InnerExtent.XMin, InnerExtent.YMax + 0.3 + 2.4 + _INNER_DIS, _DefaultColor, 0.1 * _TOPT_MM), 0);
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin, InnerExtent.YMax + 0.3 + 2.4 + _INNER_DIS, InnerExtent.XMin + 4.5, InnerExtent.YMax + 0.3 + 2.4 + _INNER_DIS, _DefaultColor, 0.1 * _TOPT_MM), 0);
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin + 4.5, InnerExtent.YMax + 0.3 + 2.4 + _INNER_DIS, InnerExtent.XMin + 4.5, InnerExtent.YMax + 0.3 + _INNER_DIS, _DefaultColor, 0.1 * _TOPT_MM), 0);
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin + 4.5, InnerExtent.YMax + 0.3 + _INNER_DIS, InnerExtent.XMin, InnerExtent.YMax + 0.3 + _INNER_DIS, _DefaultColor, 0.1 * _TOPT_MM), 0);

            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin, InnerExtent.YMax + 0.3 + _INNER_DIS + 0.8, InnerExtent.XMin + 4.5, InnerExtent.YMax + 0.3 + _INNER_DIS + 0.8, _DefaultColor, 0.1 * _TOPT_MM), 9);
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin, InnerExtent.YMax + 0.3 + _INNER_DIS + 1.6, InnerExtent.XMin + 4.5, InnerExtent.YMax + 0.3 + _INNER_DIS + 1.6, _DefaultColor, 0.1 * _TOPT_MM), 9);
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin + 1.5, InnerExtent.YMax + 0.3 + _INNER_DIS, InnerExtent.XMin + 1.5, InnerExtent.YMax + 0.3 + _INNER_DIS + 2.4, _DefaultColor, 0.1 * _TOPT_MM), 9);
            _Graphics.AddElement(ElementHelper.CreateLine(InnerExtent.XMin + 3.0, InnerExtent.YMax + 0.3 + _INNER_DIS, InnerExtent.XMin + 3.0, InnerExtent.YMax + 0.3 + _INNER_DIS + 2.4, _DefaultColor, 0.1 * _TOPT_MM), 9);

            if (Sheet != null && Sheet.UserData != null)
            {
                decimal fontsize = (decimal)(2.5 * _TOPT_MM);
                if (Sheet.UserData is List<string>)
                {
                    foreach (string s in Sheet.UserData)
                    {
                        string[] ss = s.Split(':');
                        double x = 0;
                        double y = 0;
                        switch (ss[0])
                        {
                            case SheetHelper.F_LeftTop:
                                x = InnerExtent.XMin + 0.75;
                                y = InnerExtent.YMax + _INNER_DIS + 0.3 + 2;
                                break;
                            case SheetHelper.F_TopIn:
                                x = InnerExtent.XMin + 2.25;
                                y = InnerExtent.YMax + _INNER_DIS + 0.3 + 2;
                                break;
                            case SheetHelper.F_RightTop:
                                x = InnerExtent.XMin + 3.75;
                                y = InnerExtent.YMax + _INNER_DIS + 0.3 + 2;
                                break;
                            case SheetHelper.F_LeftIn:
                                x = InnerExtent.XMin + 0.75;
                                y = InnerExtent.YMax + _INNER_DIS + 0.3 + 1.2;
                                break;
                            case SheetHelper.F_RightIn:
                                x = InnerExtent.XMin + 3.75;
                                y = InnerExtent.YMax + _INNER_DIS + 0.3 + 1.2;
                                break;
                            case SheetHelper.F_LeftUnder:
                                x = InnerExtent.XMin + 0.75;
                                y = InnerExtent.YMax + _INNER_DIS + 0.3 + 0.4;
                                break;
                            case SheetHelper.F_UnderIn:
                                x = InnerExtent.XMin + 2.25;
                                y = InnerExtent.YMax + _INNER_DIS + 0.3 + 0.4;
                                break;
                            case SheetHelper.F_RightUnder:
                                x = InnerExtent.XMin + 3.75;
                                y = InnerExtent.YMax + _INNER_DIS + 0.3 + 0.4;
                                break;
                        }
                        _Graphics.AddElement(ElementHelper.CreateText(x, y, ss[1], fontsize, esriTextHorizontalAlignment.esriTHACenter, esriTextVerticalAlignment.esriTVACenter, "华文细黑", false, 0), 9);
                    }
                }
            }
        }

        /// <summary>
        /// 绘制下边的元数据信息
        /// </summary>
        private void DrawBottomMeta(double x, double y, List<string> values)
        {
            if (values == null || values.Count == 0) return;
            decimal fontsize = (decimal)(3 * _TOPT_MM);            
            foreach (string value in values)
            { 
                IElement ele = ElementHelper.CreateText(x, y, value, fontsize, esriTextHorizontalAlignment.esriTHALeft, esriTextVerticalAlignment.esriTVATop, "华文细黑", false, 0);
                _Graphics.AddElement(ele, 9);
                double txtw = 0;
                double txth = 0;
                (ele as ITextElement).Symbol.GetTextSize(PageLayout.ActiveView.ScreenDisplay.get_CacheMemDC(0), PageLayout.ActiveView.ScreenDisplay.DisplayTransformation, value, out txtw, out txth);
                y -= (0.2 + (txth / 72 * 2.54));
            }
        }

        /// <summary>
        /// 删除绘制的Element对象
        /// </summary>
        private void DeleteElement()
        {
            if (_Graphics == null) return;
            _Graphics.Reset();
            IElement oldele = null;
            List<IElement> oldels = new List<IElement>();
            while ((oldele = _Graphics.Next()) != null)
            {
                if (!(oldele is IMapFrame)) oldels.Add(oldele);
            }
            _Graphics.Reset();
            foreach (IElement ele in oldels)
            {
                _Graphics.DeleteElement(ele);
            }
        }
    }
}
